/**
 * Copyright (C) 2010 DustedPixels.com
 */
package com.dustedpixels.cirt.model.machine.spectrum.ula;

import com.dustedpixels.cirt.model.core.Circuit;
import com.dustedpixels.cirt.model.core.In;
import com.dustedpixels.cirt.model.core.Out;
import com.dustedpixels.cirt.model.core.Pins;
import com.dustedpixels.cirt.model.core.Script;

/**
 * Memory control circuit.
 * 
 * @author Michal Pociecha-Los (micapolos@gmail.com)
 */
@Circuit
public final class MemoryControl {
  @In public int h;
  @In public int v;
  @In @Pins(8) public int data;
  
  @Out @Pins(13) public int address;
  @Out public boolean isAttr;
  @Out public boolean read;
  @Out public boolean contention;
  
  @Out public boolean screen;
  @Out public boolean ink;
  @Out @Pins(8) public int attr;

  @Pins(8) private int shiftReg;
  
  @Pins(8) private int screenReg1;
  @Pins(8) private int attrReg1;
  
  @Pins(8) private int screenReg2;
  @Pins(8) private int attrReg2;
  
  @Script
  public void update() {
    if (h == -8 && v == 0) address = 0;
    boolean vActive = (v >= 0) && (v < 192);
    boolean active = vActive && (h >= -8) && (h < 248);
    
    screen = vActive && (h >= 0) && (h < 256);

    if (screen) {
      int maskedH = h & 0x0F;
      if (maskedH == 0x00) {
        shiftReg = screenReg1;
        attr = attrReg1;
      } else if (maskedH == 0x08) {
        shiftReg = screenReg2;
        attr = attrReg2;
      }
    }
    
    if (active) {
      int cycle = (h & 0x0F) ^ 0x08;
      switch (cycle) {
        case 0:
          break;
          
        case 1:
          break;
          
        case 2:
          contention = true;
          break;
  
        case 3:
          break;
          
        case 4:
          read = true;
          isAttr = false;
          break;
          
        case 5:
          read = false;
          screenReg1 = data;
          break;
          
        case 6:
          read = true;
          isAttr = true;
          break;
          
        case 7:
          read = false;
          attrReg1 = data;
          address++;
          break;
  
        case 8:
          isAttr = false;
          read = true;
          break;
          
        case 9:
          read = false;
          screenReg2 = data;
          break;
          
        case 10:
          read = true;
          isAttr = true;
          break;
          
        case 11:
          read = false;
          attrReg2 = data;
          break;
        
        case 12:
          break;
  
        case 13:
          break;
  
        case 14:
          contention = false;
          break;
          
        case 15:
          address++;
          break;
      }
    }
    
    if (screen) {
      ink = (shiftReg & 0x80) != 0;      
      shiftReg <<= 1;
    }
  }
}
